package com.qianxun.module.application.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qianxun.framework.common.util.ObjectUtil;
import com.qianxun.module.application.common.CommonUtil;
import com.qianxun.module.application.dto.OrderDto;
import com.qianxun.module.application.entity.ApplicationDataRelation;
import com.qianxun.module.application.entity.DataSortQueryTable;
import com.qianxun.module.application.entity.RelationQueryTable;
import com.qianxun.module.application.service.ApplicationDataRelationService;
import com.qianxun.module.application.service.DataSortQueryTableService;
import com.qianxun.module.application.service.RelationQueryTableService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

/**
 * 通用业务处理类
 *
 * @author Admin
 */
@Slf4j
@Service
public class BaseServiceImpl {

    /**
     * 数据偏移量
     */
    private final static int OFFSET = 0;
    /**
     * 默认分表限制数
     */
    private final static int DEFAULT_LIMIT_COUNT = 1000000;
    /**
     * 默认表
     */
    private final static String DEFAULT_INSERT_TABLE = "application_data_relation0";

    /**
     * 插入并发锁
     */
    private final ReentrantLock lock = new ReentrantLock();

    @Resource
    private RelationQueryTableService relationQueryTableService;

    @Resource
    private ApplicationDataRelationService dataRelationService;

    @Resource
    private DataSortQueryTableService dataSortQueryTableService;

    /**
     * 数据分表操作
     *
     * @param appId    应用ID
     * @param dataType 数据类型
     * @param dataKey  数据key
     * @param sortJson 排序json
     */
    public String dealSharingTable(String appId, String dataType, String dataKey, String sortJson) {
        lock.lock();
        //1.若是appId，dataType都不为空，查询其条件的数据是否达到分表要求， 数据量：appId='xxx' and dataType='xxx'

        //2.若是appId不为空，dataType为空，查询其条件的数据是否达到分表要求 ，数据量：appId='xxx' and dataType=''

        //3.若是appId为空，dataType为空，查询其条件的数据是否达到分表要求，数据量： appId='' and dataType=''
        try {
            appId = StringUtils.isBlank(appId) ? "" : appId;
            dataType = StringUtils.isBlank(dataType) ? "" : dataType;
            String insertTableName = DEFAULT_INSERT_TABLE;

            //排序信息处理
            String value1 = null, value2 = null, value3 = null, value4 = null, value5 = null;
            if (StringUtils.isNotBlank(sortJson)) {
                Map<String, String> map = ObjectUtil.toBean(sortJson, Map.class);
                Set<String> keys = map.keySet();
                int size = keys.size();
                if (size > 5) {
                    return "排序信息已超过限制最多5个";
                }
                List<String> keyList = new ArrayList<>(keys);

                //查询并校验排序规则，不满足直接返回错误提示
                DataSortQueryTable dataSortQueryTable = dataSortQueryTableService.queryByAppIdAndDataType(appId, dataType);

                if (Objects.isNull(dataSortQueryTable)) {
                    String sort1 = null, sort2 = null, sort3 = null, sort4 = null, sort5 = null;
                    try {
                        sort1 = keyList.get(0);
                    } catch (Exception e) {
                    }
                    try {
                        sort2 = keyList.get(1);
                    } catch (Exception e) {
                    }
                    try {
                        sort3 = keyList.get(2);
                    } catch (Exception e) {
                    }
                    try {
                        sort4 = keyList.get(3);
                    } catch (Exception e) {
                    }
                    try {
                        sort5 = keyList.get(4);
                    } catch (Exception e) {
                    }

                    //没有排序规则，则定义插入
                    dataSortQueryTable = new DataSortQueryTable();
                    dataSortQueryTable.setAppId(appId);
                    dataSortQueryTable.setDataType(dataType);
                    dataSortQueryTable.setSort1Key(sort1);
                    dataSortQueryTable.setSort2Key(sort2);
                    dataSortQueryTable.setSort3Key(sort3);
                    dataSortQueryTable.setSort4Key(sort4);
                    dataSortQueryTable.setSort5Key(sort5);

                    value1 = map.get(sort1);
                    value2 = map.get(sort2);
                    value3 = map.get(sort3);
                    value4 = map.get(sort4);
                    value5 = map.get(sort5);

                    dataSortQueryTableService.save(dataSortQueryTable);

                } else {
                    //校验排序规则
                    //当前的sortKey是否包含，不包含则提示当前排序key不存在
                    List<String> sortKeyList = CommonUtil.dealSortList(dataSortQueryTable, true);

                    for (String c : keyList) {
                        if (!sortKeyList.contains(c)) {
                            return "当前排序key不满足条件：" + c;
                        }
                    }
                    value1 = map.get(sortKeyList.get(0));
                    value2 = map.get(sortKeyList.get(1));
                    value3 = map.get(sortKeyList.get(2));
                    value4 = map.get(sortKeyList.get(3));
                    value5 = map.get(sortKeyList.get(4));
                }

            }

            LambdaQueryWrapper<RelationQueryTable> wrapper = new QueryWrapper<RelationQueryTable>().lambda();
            wrapper.eq(RelationQueryTable::getAppId, appId);
            wrapper.eq(RelationQueryTable::getDataType, dataType);
            List<RelationQueryTable> list = relationQueryTableService.list(wrapper);
            RelationQueryTable last;
            if (Objects.nonNull(list) && list.size() > 0) {
                //已有分表，查询对应的
                last = list.get(list.size() - 1);
            } else {
                LambdaQueryWrapper<RelationQueryTable> wrapper1 = new QueryWrapper<RelationQueryTable>().lambda();
                wrapper1.eq(RelationQueryTable::getAppId, "");
                wrapper1.eq(RelationQueryTable::getDataType, "");
                List<RelationQueryTable> list1 = relationQueryTableService.list(wrapper1);
                last = list1.get(list1.size() - 1);
            }

            //限制数
            Integer limit = last.getDataCount();
            //指定已到达数
            if (Objects.nonNull(limit) && limit.intValue() != 0) {
                String tableName = last.getRelationTableName();
                insertTableName = tableName;
                int useCount = dataRelationService.queryCount(tableName, appId, dataType);
                if (useCount >= (limit - OFFSET)) {
                    //满足分表
                    //查询最后表
                    LambdaQueryWrapper<RelationQueryTable> wrapper2 = new QueryWrapper<RelationQueryTable>().lambda();
                    wrapper2.select(RelationQueryTable::getRelationTableName);
                    List<RelationQueryTable> tables = relationQueryTableService.list(wrapper2);
                    RelationQueryTable table = tables.get(tables.size() - 1);
                    String lastTableName = table.getRelationTableName();

                    int v = Integer.parseInt(lastTableName.substring(lastTableName.length() - 1, lastTableName.length()));
                    String name = lastTableName.substring(0, lastTableName.length() - 1);
                    String newTableName = name + (v + 1);
                    try {
                        dataRelationService.createTable(newTableName);
                    } catch (Exception e) {
                        log.debug(newTableName + " 表已存在 -->>>", e.getMessage());
                    }
                    //创建成功
                    insertTableName = newTableName;
                    RelationQueryTable relationQueryTable = new RelationQueryTable();
                    relationQueryTable.setDataCount(DEFAULT_LIMIT_COUNT);
                    relationQueryTable.setAppId(appId);
                    relationQueryTable.setDataType(dataType);
                    relationQueryTable.setRelationTableName(insertTableName);
                    relationQueryTableService.save(relationQueryTable);
                    //迁移数据
                    try {
                        if (!insertTableName.equals(DEFAULT_INSERT_TABLE)) {
                            dataRelationService.copyData(insertTableName, DEFAULT_INSERT_TABLE, appId, dataType);
                            dataRelationService.deleteData(DEFAULT_INSERT_TABLE, appId, dataType);
                        }
                    } catch (Exception e) {
                        log.debug("迁移数据出错-->>>", e.getMessage());
                    }
                }
            }

            //插入数据操作
            Date curr = new Date();
            dataRelationService.insertIntoTable(insertTableName, appId, dataType, dataKey, curr, value1, value2, value3, value4, value5);
        } finally {
            lock.unlock();
        }

        return null;
    }

    /**
     * 分页查询数据
     *
     * @param appId    应用ID
     * @param dataType 数据类型
     * @param dataKey  数据key
     * @param sortJson 排序信息
     * @param page     分页信息
     * @return
     */
    public List<ApplicationDataRelation> queryDataPage(String appId, String dataType, String dataKey, String sortJson, Page<ApplicationDataRelation> page) {
        List<ApplicationDataRelation> relationList = null;
        if (lock.isLocked()) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                log.error(e.getMessage());
            }
        }
        if (!lock.isLocked()) {
            //排序
            Set<Map<String, String>> sortList = dealSort(sortJson, appId, dataType);
            appId = StringUtils.isBlank(appId) ? "" : appId;
            dataType = StringUtils.isBlank(dataType) ? "" : dataType;
            LambdaQueryWrapper<RelationQueryTable> wrapper = new QueryWrapper<RelationQueryTable>().lambda();
            wrapper.eq(RelationQueryTable::getAppId, appId);
            wrapper.eq(RelationQueryTable::getDataType, dataType);
            List<RelationQueryTable> list = relationQueryTableService.list(wrapper);
            List<String> tables;
            if (Objects.nonNull(list) && list.size() > 0) {
                //查询分表里满足条件的所有数据，并整合
                tables = list.stream().map(RelationQueryTable::getRelationTableName).collect(Collectors.toList());
            } else {
                //查询通用数据
                tables = new ArrayList<>();
                tables.add(DEFAULT_INSERT_TABLE);
            }
            relationList = dataRelationService.selectByPage(tables, appId, dataType, dataKey, sortList, page);
        }
        return relationList;
    }

    /**
     * 处理排序信息
     *
     * @param sortJson 排序json
     * @param appId    应用ID
     * @param dataType 数据类型
     * @return
     */
    private Set<Map<String, String>> dealSort(String sortJson, String appId, String dataType) {
        //排序
        Set<Map<String, String>> sortList = new HashSet<>();
        if (StringUtils.isNotBlank(sortJson)) {
            List<OrderDto> orderDtos = JSON.parseArray(sortJson, OrderDto.class);
            List<String> myOrder = orderDtos.stream().map(OrderDto::getOrderName).collect(Collectors.toList());
            List<String> myOrderBy = orderDtos.stream().map(OrderDto::getOrderBy).collect(Collectors.toList());
            DataSortQueryTable dataSortQueryTable = dataSortQueryTableService.queryByAppIdAndDataType(appId, dataType);
            if (Objects.nonNull(dataSortQueryTable)) {
                List<String> sortKeyList = CommonUtil.dealSortList(dataSortQueryTable, false);
                for (int i = 0; i < myOrder.size(); i++) {
                    for (int j = 0; j < sortKeyList.size(); j++) {
                        String s = sortKeyList.get(j);
                        if (StringUtils.isNotBlank(s) && myOrder.get(i).equals(s)) {
                            String orderBy = myOrderBy.get(i);
                            Map<String, String> map = new HashMap<>();
                            map.put("orderName", "sort" + (j + 1));
                            map.put("orderByStr", orderBy);
                            sortList.add(map);
                        }
                    }
                }
            }
        }
        return sortList.size() > 0 ? sortList : null;
    }
}
